<template>
  <view
    class="tui-waterfall__box"
    :style="{
      paddingLeft: leftGap,
      paddingRight: rightGap,
      background: backgroundColor,
      borderRadius: radius,
    }"
  >
    <view class="tui-waterfall__list" id="tui-waterfall__left" :style="{ marginRight: columnGap }">
      <view v-for="(item, index) in leftList" :key="index">
        <slot name="left" :entity="item" :index="index" :isList="columnCount == 1"></slot>
      </view>
    </view>
    <view v-if="columnCount > 1" class="tui-waterfall__list" id="tui-waterfall__right">
      <view v-for="(item, index) in rightList" :key="index">
        <slot name="right" :entity="item" :index="index" :isList="columnCount == 1"></slot>
      </view>
    </view>
  </view>
</template>

<script>
/**
 * 列表中图片可以使用懒加载或者其他方式
 * 优先计算出图片高度,以达到最佳效果
 * App端建议使用weex的waterfall组件，使用案例详见：
 * [ThorUI组件库->pages->index->productNvue]
 */
export default {
  name: 'tuiWaterfall',
  props: {
    //列表数据，不建议一次性加载过多数据
    listData: {
      type: Array,
      default() {
        return [];
      },
    },
    //每页数据条数(固定条数),当总数据长度小于等于该数时表示第一页数据，刷新重置
    pageSize: {
      type: Number,
      default: 10,
    },
    //数据分组类型：1-简单左右分组，按顺序排列，伪瀑布流 2-计算左右容器高度进行分组
    type: {
      type: Number,
      default: 1,
    },
    //瀑布流列数，目前支持最大值为2
    columnCount: {
      type: Number,
      default: 2,
    },
    //列与列的间隙
    columnGap: {
      type: String,
      default: '10rpx',
    },
    //左侧和列表的间隙
    leftGap: {
      type: String,
      default: '0',
    },
    //右侧和列表的间隙
    rightGap: {
      type: String,
      default: '0',
    },
    //列表背景色，可使用渐变色
    backgroundColor: {
      type: String,
      default: 'transparent',
    },
    //列表外层容器圆角值
    radius: {
      type: String,
      default: '0',
    },
  },
  data() {
    return {
      leftListConst: [],
      leftList: [],
      rightList: [],
      init: true,
    };
  },
  watch: {
    listData(val) {
      if (!this.init) {
        this.columnChange();
      }
    },
    columnCount(val) {
      this.columnChange(val);
    },
  },
  mounted() {
    this.init = false;
    this.columnChange();
  },
  methods: {
    columnChange(val) {
      if (this.columnCount < 2) {
        this.leftList = [...this.listData];
      } else {
        if (val && val == 2) {
          this.leftList = [...this.leftListConst];
        }
        this.initData();
      }
    },
    initData() {
      if (this.type == 1) {
        this.getSubGroup();
      } else {
        this.getArrayByHeight();
      }
    },
    getDiffList() {
      let diffList = [];
      let total = this.listData.length;
      if (total <= this.pageSize) {
        this.leftListConst = [];
        this.leftList = [];
        this.rightList = [];
      }
      let sum = this.leftListConst.length + this.rightList.length;
      let diff = total - sum;
      if (diff > 0) {
        diffList = [...this.listData].filter((item, index) => {
          return index >= sum;
        });
      }
      return diffList;
    },
    getSubGroup() {
      //type=1时执行简单数据分组
      if (!this.listData && this.listData.length === 0) return;
      let leftList = [];
      let rightList = [];
      let data = this.getDiffList();
      data.forEach((item, index) => {
        if (index % 2 === 0) {
          leftList.push(item);
        } else {
          rightList.push(item);
        }
      });
      this.leftList = this.leftList.concat(leftList);
      this.leftListConst = this.leftListConst.concat(leftList);
      this.rightList = this.rightList.concat(rightList);
    },
    async getArrayByHeight() {
      if (!this.listData && this.listData.length === 0) return;
      let data = this.getDiffList();
      for (let item of data) {
        await this.render(item);
      }
    },
    sleep(millisecond) {
      let now = new Date();
      let exitTime = now.getTime() + millisecond;
      while (true) {
        now = new Date();
        if (now.getTime() > exitTime) return;
      }
    },
    async render(item) {
      this.sleep(50);
      let obj = await this.getContainerHeight();
      return await new Promise((resolve, reject) => {
        if (obj && typeof obj.leftHeight === 'number') {
          if (obj.leftHeight <= obj.rightHeight) {
            this.leftList.push(item);
            this.leftListConst.push(item);
          } else {
            this.rightList.push(item);
          }
          resolve(true);
        } else {
          reject(false);
        }
      });
    },
    async getContainerHeight() {
      //type=2
      return await new Promise((resolve, reject) => {
        const query = uni.createSelectorQuery().in(this);
        let nodes = query.selectAll('#tui-waterfall__left, #tui-waterfall__right');
        nodes.boundingClientRect().exec((res) => {
          if (res && res[0]) {
            const rects = res[0];
            const leftHeight = rects[0].height;
            const rightHeight = rects[1].height;
            resolve({
              leftHeight: leftHeight,
              rightHeight: rightHeight,
            });
          } else {
            reject(res);
          }
        });
      });
    },
  },
};
</script>

<style scoped>
.tui-waterfall__box {
  width: 100%;
  display: inline-flex;
  justify-content: space-between;
  flex-direction: row;
  flex-wrap: wrap;
  box-sizing: border-box;
  align-items: flex-start;
}

.tui-waterfall__list {
  flex: 1;
}
</style>
